package com.wk.code.wkserver.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wk.code.wkserver.constant.Constant;
import com.wk.code.wkserver.constant.EmailConstant;
import com.wk.code.wkserver.constant.NumberConstant;
import com.wk.code.wkserver.constant.enums.TechApplyRecordStatusEnum;
import com.wk.code.wkserver.constant.enums.UserTypeEnum;
import com.wk.code.wkserver.entity.TechApplyRecord;
import com.wk.code.wkserver.entity.User;
import com.wk.code.wkserver.entity.UserAccount;
import com.wk.code.wkserver.entity.UserInfo;
import com.wk.code.wkserver.exception.BizException;
import com.wk.code.wkserver.manager.WeixinManager;
import com.wk.code.wkserver.mapper.UserMapper;
import com.wk.code.wkserver.request.admin.TechUserVerifyRequest;
import com.wk.code.wkserver.request.app.UserRequest;
import com.wk.code.wkserver.request.app.WxLoginRequest;
import com.wk.code.wkserver.request.app.WxUserInfoRequest;
import com.wk.code.wkserver.response.admin.TechApplyRecordResponse;
import com.wk.code.wkserver.response.admin.UserBalanceRecord;
import com.wk.code.wkserver.response.admin.UserInfoDetailResponse;
import com.wk.code.wkserver.response.app.AppUserInfoResponse;
import com.wk.code.wkserver.response.app.WxSessionResponse;
import com.wk.code.wkserver.response.base.PageInfo;
import com.wk.code.wkserver.service.*;
import com.wk.code.wkserver.utils.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * User 实现层
 *
 * @Author wq
 * @Date 2021-03-16
 **/
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private TokenUtils tokenUtils;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private IUserInfoService userInfoService;

    @Resource
    private IUserAccountService userAccountService;

    @Resource
    private IUserAccountRecordService userAccountRecordService;

    @Resource
    private WeixinManager weixinManager;

    @Resource
    private ITechTypeService techTypeService;

    @Resource
    private ITechApplyRecordService techApplyRecordService;

    @Resource
    private IMailService mailService;

    @Resource
    private IDemandService demandService;

    @Resource
    private IDemandOrderService demandOrderService;

    @Resource
    private ISourceCodeService sourceCodeService;

    @Override
    public PageInfo<User> page(UserRequest request) {

        IPage<User> page = new Page<>(request.getPageNumber(), request.getPageSize());
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        if (Objects.nonNull(request.getUserId())) {
            wrapper.eq(User::getId, request.getUserId());
        }
        if (StringUtils.isNotEmpty(request.getNickname())) {
            wrapper.like(User::getNickname, request.getNickname());
        }
        wrapper.eq(User::getRegisterType, request.getRegisterType());
        wrapper.orderByDesc(User::getCreateTime);
        List<User> records = baseMapper.selectPage(page, wrapper).getRecords();
        if (!CollectionUtils.isEmpty(records)) {
            return new PageInfo<>(page.getTotal(), records);
        }
        return null;
    }

    @Override
    public UserInfoDetailResponse detail(Integer userId) {
        User user = baseMapper.selectById(userId);
        UserInfo userInfo = userInfoService.getOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getUserId, userId));
        if (Objects.nonNull(user)) {
            //需求用户
            if (user.getRegisterType().equals(UserTypeEnum.DEMAND_USER.getCode())) {
                if (Objects.nonNull(userInfo)) {
                    UserInfoDetailResponse response = new UserInfoDetailResponse();
                    response.setEmail(userInfo.getEmail());
                    response.setUsername(user.getNickname());
                    response.setMobile(user.getMobile());
                    response.setUserId(user.getId());
                    response.setAvatar(user.getAvatar());
                    response.setQqAccount(userInfo.getQqAccount());
                    response.setWechatAccount(userInfo.getWechatAccount());
                    response.setCity(userInfo.getCity());
                    response.setProvince(userInfo.getProvince());
                    response.setCountry(userInfo.getCountry());
                    //发单数量
                    Integer count = demandService.acquireDemandCount(userInfo.getUserId());
                    response.setDemandCount(count);
                    //查询申请记录
                    buildTechApplyRecord(user, response);
                    return response;
                }
            } else {
                //技术用户
                UserInfoDetailResponse response = new UserInfoDetailResponse();
                response.setEmail(userInfo.getEmail());
                response.setUsername(user.getNickname());
                response.setMobile(user.getMobile());
                response.setUserId(user.getId());
                response.setAvatar(user.getAvatar());
                response.setQqAccount(userInfo.getQqAccount());
                response.setWechatAccount(userInfo.getWechatAccount());
                response.setAlipayAccount(userInfo.getAlipayAccount());
                response.setRealName(userInfo.getRealName());
                response.setCity(userInfo.getCity());
                response.setProvince(userInfo.getProvince());
                response.setCountry(userInfo.getCountry());
                response.setTechTypeName(techTypeService.detail(userInfo.getTechTypeId()).getName());
                //查询用户的余额
                UserAccount userAccount = userAccountService.selectUserAccount(userId);
                response.setBalance(userAccount.getBalance());
                //设置技术接单数量
                Integer takeOrderCount = demandService.selectUserTakeOrderCount(user.getId());
                response.setTakeOrderCount(takeOrderCount);
                //技术用户设置账户记录
                List<UserBalanceRecord> list = userAccountRecordService.selectRecordList(user.getId());
                response.setUserBalanceRecords(list);
                return response;
            }
        }

        return null;
    }

    private void buildTechApplyRecord(User user, UserInfoDetailResponse response) {
        List<TechApplyRecord> list = techApplyRecordService.list(new LambdaQueryWrapper<TechApplyRecord>().eq(TechApplyRecord::getUserId, user.getId()));
        if (!CollectionUtils.isEmpty(list)) {
            List<TechApplyRecordResponse> responseList = list.stream().map(x -> {
                TechApplyRecordResponse recordResponse = new TechApplyRecordResponse();
                recordResponse.setApplyTime(DateUtils.localDateTime2Date(x.getCreateTime()));
                recordResponse.setVerifyStatus(x.getVerifyStatus());
                recordResponse.setId(x.getId());
                recordResponse.setRemark(x.getRemark());
                return recordResponse;
            }).collect(Collectors.toList());
            response.setTechApplyRecordResponses(responseList);
        }
    }

    @Override
    public void logout(HttpServletRequest request) {
        tokenUtils.logout(request);
    }


    /**
     * 创建用户账户
     *
     * @param userId 用户ID
     */
    private void createUserAccount(Integer userId) {
        userAccountService.createUserAccount(userId);
    }

    /**
     * 创建用户基本信息
     *
     * @param userId 用户ID
     */
    private void createUserInfo(Integer userId, WxUserInfoRequest request) {
        userInfoService.createUserInfo(userId, request);
    }

    @Override
    public User selectById(Integer userId) {
        return baseMapper.selectById(userId);
    }


    @Override
    public String loginCode(WxLoginRequest request) {
        if (StringUtils.isEmpty(request.getCode())) {
            throw new BizException("微信授权码获取失败");
        }
        //根据code 获取openId
        String openId = weixinManager.sessionCode(request.getCode()).getOpenId();
        if (StringUtils.isEmpty(openId)) {
            throw new BizException("微信openId获取失败");
        }
        log.warn("登录传入的参数为: " + JSONObject.toJSONString(request));
        User selectOne = baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getOpenId, openId));
        if (Objects.isNull(selectOne)) {
            //注册创建用户
            User user = createUser(request, openId);
            //创建用户基本信息表
            createUserInfo(user.getId(), request.getWxUserInfoRequest());
            //创建用户账户表
            createUserAccount(user.getId());
            long expireTime = GeneratorUtil.generateExpireTime(Constant.CONST_ONE_MONTH);
            //登录成功创建令牌
            String token = JwtUtil.createUserToken(user, expireTime);
            redisUtils.hset(Constant.USER_TOKEN_MAP, user.getId().toString(), "" + expireTime);
            return token;
        } else {
            String avatarUrl = request.getWxUserInfoRequest().getAvatarUrl();
            //更新用户头像
            selectOne.setAvatar(avatarUrl);
            updateById(selectOne);
            long expireTime = GeneratorUtil.generateExpireTime(Constant.CONST_ONE_MONTH);
            //登录成功创建令牌
            String token = JwtUtil.createUserToken(selectOne, expireTime);
            redisUtils.hset(Constant.USER_TOKEN_MAP, selectOne.getId().toString(), "" + expireTime);
            return token;
        }
    }

    @Override
    public void applyVerifyTech(Integer sysUserId, TechUserVerifyRequest request) {
        //修改用户状态
        User user = baseMapper.selectById(request.getUserId());
        //审核通过
        if (request.getVerifyStatus().equals(TechApplyRecordStatusEnum.VERIFY_PASS.getCode())) {
            if (Objects.nonNull(user)) {
                user.setRegisterType(UserTypeEnum.TECHNOLOGY_USER.getCode());
            }
            updateById(user);
            //修改审核记录表
            updateTechVerifyRecord(request.getUserId(), sysUserId, request.getVerifyStatus(), request.getRemark());
            //发送邮件通知
            //sendTechMail(TechApplyRecordStatusEnum.VERIFY_PASS.getCode(), user, null);
        } else {
            //不通过
            //修改审核记录表
            updateTechVerifyRecord(request.getUserId(), sysUserId, request.getVerifyStatus(), request.getRemark());
            //发送邮件通知
            //sendTechMail(TechApplyRecordStatusEnum.VERIFY_REJECT.getCode(), user, request.getRemark());
        }
    }

    @Override
    public AppUserInfoResponse userInfo(Integer userId) {
        User user = baseMapper.selectById(userId);
        AppUserInfoResponse response = new AppUserInfoResponse();
        if (Objects.nonNull(user)) {
            response.setNickname(user.getNickname());
            response.setUserId(user.getId());
            response.setIsTechAuth(user.getRegisterType());
            response.setIsAuth(user.getIsAuth());
            response.setAvatar(user.getAvatar());
            if (StringUtils.isNotEmpty(user.getMobile())) {
                response.setMobile(DataUtils.hidePhoneNo(user.getMobile()));
            }
            //设置需求数量
            Integer demandCount = demandService.selectUserDemandCount(userId);
            response.setDemandCount(demandCount);
            Integer codeCount = sourceCodeService.selectUserCodeCount(userId);
            response.setCodeCount(codeCount);
            //设置总收入
            UserAccount userAccount = userAccountService.selectUserAccount(userId);
            if (Objects.nonNull(userAccount)) {
                response.setTotalIncome((userAccount.getBalance()));
            }
            //设置预计入账
            BigDecimal estimateAccount = demandOrderService.selectEstimateAccount(userId);
            response.setEstimateIncome((estimateAccount));
            return response;

        }
        return null;
    }

    @Override
    public AppUserInfoResponse loginMobile(WxLoginRequest request) {
        AppUserInfoResponse response = new AppUserInfoResponse();
        WxSessionResponse wxSessionResponse = weixinManager.sessionCode(request.getCode());
        if (Objects.nonNull(wxSessionResponse)) {
            String openId = wxSessionResponse.getOpenId();
            if (StringUtils.isEmpty(openId)) {
                throw new BizException("微信一键登录失败");
            }
            User user = baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getOpenId, openId));
            if (Objects.isNull(user)) {
                throw new BizException("微信一键登录失败");
            }
            String mobile = "";
            try {
                mobile = weixinManager.getWxMiniPhone(wxSessionResponse.getSessionKey(), request.getWxLoginEncodeRequest().getIv(), request.getWxLoginEncodeRequest().getEncryptedData());
            } catch (Exception e) {
                e.printStackTrace();
                log.error("获取手机号失败");
            }
            user.setMobile(mobile);
            updateById(user);
            response.setMobile(mobile);
        }
        return response;
    }

    @Override
    public void updateUserStatus(Integer userId) {
        baseMapper.updateUserStatus(userId);
    }

    /**
     * 发送技术邮件审核通知
     *
     * @param verifyStatus 审核状态
     * @param user         用户
     */
    private void sendTechMail(Integer verifyStatus, User user, String remark) {
        UserInfo info = userInfoService.getOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getUserId, user.getId()));
        if (Objects.nonNull(info)) {
            if (StringUtils.isNotEmpty(info.getEmail())) {
                if (verifyStatus.equals(TechApplyRecordStatusEnum.VERIFY_PASS.getCode())) {
                    mailService.sendMail(info.getEmail(), String.format(EmailConstant.TECH_USER_VERIFY_PASS, user.getNickname()));
                } else {
                    mailService.sendMail(info.getEmail(), String.format(EmailConstant.TECH_USER_VERIFY_REJECT, user.getNickname(), remark));
                }
            }
        }
    }

    /**
     * 更新用户审核记录表
     *
     * @param userId       用户ID
     * @param sysUserId    系统用户ID
     * @param verifyStatus 审核状态
     * @param remark       备注
     */
    private void updateTechVerifyRecord(Integer userId, Integer sysUserId, Integer verifyStatus, String remark) {
        TechApplyRecord record = techApplyRecordService.getOne(new LambdaQueryWrapper<TechApplyRecord>().eq(TechApplyRecord::getUserId, userId).orderByDesc(TechApplyRecord::getCreateTime).
                last("limit 1"));
        if (Objects.nonNull(record)) {
            record.setSysUserId(sysUserId);
            record.setVerifyStatus(verifyStatus);
            record.setRemark(remark);
            techApplyRecordService.updateById(record);
            //删除该数据
            techApplyRecordService.removeById(record.getId());
        }
    }

    /**
     * 保存微信用户
     *
     * @param request 请求参数
     * @param openId  openId
     */
    private User createUser(WxLoginRequest request, String openId) {
        User user = new User();
        user.setOpenId(openId);
        user.setNickname(request.getWxUserInfoRequest().getNickName());
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user.setStatus(NumberConstant.ONE);
        user.setGender(request.getWxUserInfoRequest().getGender());
        user.setAvatar(request.getWxUserInfoRequest().getAvatarUrl());
        //微信登录默认都是发单用户类型为1
        user.setRegisterType(UserTypeEnum.DEMAND_USER.getCode());
        save(user);
        return user;
    }
}